package org.lboot.starter.aspect;

import cn.hutool.cache.Cache;
import cn.hutool.cache.CacheUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.extra.servlet.JakartaServletUtil;
import cn.hutool.extra.servlet.ServletUtil;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.lboot.core.auth.AuthService;
import org.lboot.core.domain.ErrMsg;
import org.lboot.core.exception.BusinessException;
import org.lboot.starter.anno.FormLock;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;



import java.lang.reflect.Method;
import java.util.Date;

/**
 * @author kindear
 * 排除 Redis 强制依赖引入
 */
@Slf4j
@Aspect
@Component
@ConditionalOnMissingBean(FormLockAspect.class)
public class MissFormLockAspect {

    private static final Cache<String, DateTime> cache = CacheUtil.newLRUCache(100);

    @Resource
    AuthService authService;




    @Pointcut("@annotation(org.lboot.starter.anno.FormLock)")
    public void FormLock(){}

    @Before("FormLock()")
    public void doBefore(JoinPoint joinPoint) {
        //获取当前请求对象
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;
        HttpServletRequest request = attributes.getRequest();
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        // 获取自定义注解信息
        FormLock formLock = method.getAnnotation(FormLock.class);
        // 获取锁定 前缀
        String key = formLock.key();
        if (Validator.isEmpty(key)){
            key = formLock.value();
        }
        // 锁定时长 单位 s
        int sec = formLock.sec();
        // 判断登录态
        Boolean isLogin = authService.isLogin();

        // 如果是登录态根据 token 拦截
        if (isLogin){
            // 获取当前登录用户ID
            String loginId = authService.getUid();
            String lockKey = key+":"+loginId;
            DateTime expireDate = cache.get(lockKey);
            Date now = DateUtil.date();
            if (Validator.isEmpty(expireDate)){
                // 过期时间
                expireDate = DateUtil.offsetSecond(now, sec);
                cache.put(lockKey, expireDate);
            }else {
                // 已经过期，重新上锁
                if (expireDate.isBefore(now)){
                    expireDate = DateUtil.offsetSecond(now, sec);
                    cache.put(lockKey, expireDate);
                }else {
                    // 尚未过期，抛出异常
                    throw new BusinessException(HttpStatus.FORBIDDEN, ErrMsg.build("请不要重复请求"));
                }

            }
        }else {
            String clientIp = JakartaServletUtil.getClientIP(request);
            String lockKey = key+":"+clientIp;
            DateTime expireDate = cache.get(lockKey);
            Date now = DateUtil.date();
            if (Validator.isEmpty(expireDate)){
                // 过期时间
                expireDate = DateUtil.offsetSecond(now, sec);
                cache.put(lockKey, expireDate);
            }else {
                // 已经过期，重新上锁
                if (expireDate.isBefore(now)){
                    expireDate = DateUtil.offsetSecond(now, sec);
                    cache.put(lockKey, expireDate);
                }else {
                    // 尚未过期，抛出异常
                    throw new BusinessException(HttpStatus.FORBIDDEN, ErrMsg.build("请不要重复请求"));
                }
            }
        }
    }
}
